﻿using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

namespace Miao.Editor
{
    public class UndoSystem
    {
        public event Action onUndo;
        public event Action onRedo;

        private int index = -1;

        private readonly UndoObject undoObject;
        private readonly List<IUndoCommand> undoCommandList = new List<IUndoCommand>();

        public UndoSystem()
        {
            undoObject = ScriptableObject.CreateInstance<UndoObject>();
            undoObject.hideFlags = HideFlags.HideAndDontSave;
            undoObject.onUndo += () => EditorApplication.delayCall += OnUndo;
            undoObject.onRedo += () => EditorApplication.delayCall += OnRedo;
        }

        public void AddCommand(IUndoCommand undoCommand)
        {
            int startIndex = index + 1;
            undoCommandList.RemoveRange(startIndex, undoCommandList.Count - startIndex);

            index++;
            undoCommandList.Add(undoCommand);

            global::UnityEditor.Undo.IncrementCurrentGroup();
            global::UnityEditor.Undo.RegisterCompleteObjectUndo(undoObject, undoCommand.info);
            undoObject.Record();
        }
        /// <summary>
        /// Clears all undo command recorded by this <see cref="UndoSystem"/>.
        /// </summary>
        public void Clear()
        {
            index = -1;
            global::UnityEditor.Undo.ClearUndo(undoObject);
            undoCommandList.Clear();
        }

        private void OnRedo()
        {
            IUndoCommand undoCommand = undoCommandList[++index];
            undoCommand.Redo();
            onRedo?.Invoke();
        }
        private void OnUndo()
        {
            IUndoCommand undoCommand = undoCommandList[index--];
            undoCommand.Undo();
            onUndo?.Invoke();
        }
    }
}